package services

import (
	"goravel/app/models"
	"goravel/app/scopes"

	"github.com/goravel/framework/contracts/http"
)

type CategoryService struct{}

func NewCategoryService() *CategoryService {
	return &CategoryService{}
}

// GetAllCategories 获取所有构建树形结构
func (s *CategoryService) GetAllCategories(ctx http.Context) ([]map[string]any, error) {
	var model []models.Categorie

	query := scopes.Query(ctx)

	dataType := ctx.Request().Input("type")
	if ctx.Request().Input("type") != "" {
		query = query.Where("type = ?", dataType)
	}

	if err := query.Find(&model); err != nil {
		return nil, err
	}

	return buildTree(model), nil
}

// GetSubordinateIDs 获取指定的所有下级 ID
func (s *CategoryService) GetSubordinateIDs(ctx http.Context, id uint) ([]uint, error) {
	var model []models.Categorie
	if err := scopes.Query(ctx).Find(&model); err != nil {
		return nil, err
	}

	modelMap := make(map[uint]*models.Categorie)
	for i := range model {
		modelMap[model[i].ID] = &model[i]
	}

	return getSubordinateIDs(id, modelMap), nil
}

// 将扁平列表转换为树形结构
func buildTree(model []models.Categorie) []map[string]any {
	var tree []map[string]any
	modelMap := make(map[uint]*models.Categorie)

	// 将所有分类放入 map 中
	for i := range model {
		modelMap[model[i].ID] = &model[i]
	}

	// 构建树形结构
	for i := range model {
		category := &model[i]
		if category.ParentID == 0 {
			tree = append(tree, buildModelTree(category, modelMap))
		}
	}

	return tree
}

// 递归构建树形结构
func buildModelTree(model *models.Categorie, modelMap map[uint]*models.Categorie) map[string]any {
	node := map[string]any{
		"id":    model.ID,
		"label": model.Name,
		"sort":  model.Sort,
	}

	// 查找子节点
	var children []map[string]any
	for _, cat := range modelMap {
		if cat.ParentID == model.ID {
			children = append(children, buildModelTree(cat, modelMap))
		}
	}

	if len(children) > 0 {
		node["children"] = children
	}

	return node
}

// 递归获取传入 ID 的所有下级 ID
func getSubordinateIDs(id uint, modelMap map[uint]*models.Categorie) []uint {
	var ids []uint
	ids = append(ids, id)

	// 查找直接子级
	for _, cat := range modelMap {
		if cat.ParentID == id {
			ids = append(ids, getSubordinateIDs(cat.ID, modelMap)...)
		}
	}

	return ids
}
